package com.lsh.streamgd.excelExtractor;

import com.hp.hpl.jena.rdf.model.Model;
import com.hp.hpl.jena.rdf.model.RDFNode;
import com.hp.hpl.jena.rdf.model.Resource;
import com.hp.hpl.jena.vocabulary.DC;
import com.hp.hpl.jena.vocabulary.OWL;
import com.hp.hpl.jena.vocabulary.RDF;
import com.hp.hpl.jena.vocabulary.RDFS;
import com.lsh.streamgd.utils.StringUtil;
import com.lsh.streamgd.vocabulary.USS;
import org.apache.any23.rdf.RDFUtils;
import org.apache.commons.lang3.StringUtils;
import org.openrdf.model.URI;
import org.openrdf.model.impl.URIImpl;

import java.io.File;
import java.util.StringTokenizer;

public class MultiThreadExtractor {
    //自动生成
    private static String version = "1.0";
    private static String creator = "seminfo";

    //页面传输
    private static String lang = "zh"; //修改，数据集label的语种
    private static String agent_uri = "szjtj_cn"; //机构英文
    private static String title = "深圳市司法局"; //机构中文
    private static String header = "1,2,3,4,5,6,7,8,9,10,11,12,13"; //无表头时，需要填入
//    private static String header = ""; //无表头时，需要填入
//    private static String header_zh = "单位,地址,联系电话"; //无表头或1行表头时，需要填入
    private static String header_zh = "1,2,3,4,5,6,7,8,9,10,11,12,13"; //无表头或1行表头时，需要填入
    private static String file_name = "d:\\ytq_czxxb.csv"; //需要转换的文件名
    private static String class_name = "ytq_czxxb"; //需要转换的类名
    private static String class_label = "公证处名录"; //修改
    private static String code = "UTF8"; //文件编码

    //配置文件
    private static String domain = "http://www.szcodi.com"; //从配置文件中获取
    private static int blockSize = 100000; //放入配置文件中：三元组分割数量
    private static int threadNum = 5; //放入配置文件中：多线程数量
    private static String path = "d:\\"; //放入配置文件中：存储目录

    private static String baseUri = domain + "/graph/" + agent_uri;
    private static File file = new File(file_name);
    private static String classUri = baseUri + "/" + class_name;
    private static String instanceUri = baseUri.replaceAll("/ontology/", "/resource/");

    private String message;

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }

//    public static void main(String[] args) throws IOException, ExtractionException {
//        //生成owl本体model
//        Configuration configuration = DefaultConfiguration.singleton();
//        configuration.getProperties();
//
//        ExtractionContext ctx = new ExtractionContext("CSV", new URIImpl(baseUri));
//        ctx.setClassURI(classUri);
//        ctx.setInstanceURI(instanceUri);
//        ctx.setClassLabel(class_label);
//        ctx.setBaseURI(baseUri);
//        ctx.setVersion(version);
//        ctx.setCreator(creator);
//        ctx.setTitle(title);
//        ctx.setLang(lang);
//        ctx.setCode(code);
//
//        URI[] headerURI = null;
////        MultiThreadExtractor main = new MultiThreadExtractor();
//        String[] headers = null, headers_zh = null;
//        int start_index = 0;
//
//        //英文表头不为空
//        if (!StringUtil.isBlank(header)) {
//            if (!StringUtil.isBlank(header_zh)) {
//                //中英文表头都不为空
//                headers = header.split(",");
//                headers_zh = header_zh.split(",");
//            } else {
//                //中文表头从文件获取，英文表头从页面获取
//                headers = header.split(",");
//                //获取第一行数据
//                InputStreamReader isr = new InputStreamReader(new FileInputStream(file), code);
//                BufferedReader br = new BufferedReader(isr);
//
//                String lineTxt = null;
//                while((lineTxt = br.readLine()) != null){
//                    headers_zh = CSVUtils.parseLine(lineTxt).toArray(new String[]{});
//                    start_index = lineTxt.getBytes().length + 2;
//                    break;
//                }
//
//                br.close();
//                isr.close();
//            }
//        } else {
//            if (!StringUtil.isBlank(header_zh)) {
//                //中文表头不为空，从页面获取；英文表头从文件获取
//                headers_zh = header_zh.split(",");
//                //获取第一行数据
//                InputStreamReader isr = new InputStreamReader(new FileInputStream(file), code);
//                BufferedReader br = new BufferedReader(isr);
//
//                String lineTxt = null;
//                while((lineTxt = br.readLine()) != null){
//                    headers = CSVUtils.parseLine(lineTxt).toArray(new String[]{});
//                    start_index = lineTxt.getBytes().length + 2;
//                    break;
//                }
//
//                br.close();
//                isr.close();
//            } else {
//                //都为空，CSV文件里含有中英文表头
//                InputStreamReader isr = new InputStreamReader(new FileInputStream(file), code);
//                BufferedReader br = new BufferedReader(isr);
//
//                String lineTxt = null;
//                int count = 1;
//                while((lineTxt = br.readLine()) != null){
//                    if (count == 1) {
//                        headers = CSVUtils.parseLine(lineTxt).toArray(new String[]{});
//                        start_index += lineTxt.getBytes().length + 2;
//                    }
//
//                    if (count == 2) {
//                        headers_zh = CSVUtils.parseLine(lineTxt).toArray(new String[]{});
//                        start_index += lineTxt.getBytes().length + 2;
//                        break;
//                    }
//
//                    count ++;
//                }
//
//                br.close();
//                isr.close();
//            }
//        }
//
//        headerURI = processHeader(headers, new URIImpl(baseUri));
//
//        File directory = new File(path + "/" + title + "/" + class_label);
//        if (directory.mkdirs()) {
//        }
//
//        //生成OwlModel信息
//        Model owl_model = ModelFactory.createDefaultModel();
//        addGraphStatements(owl_model, ctx);
//        generateOWLStatements(owl_model, headerURI, headers, headers_zh, ctx);
//
//        //保存owl本体文件
//        OutputStream f = new FileOutputStream(path + "/" + title + "/" + class_label + "/" + class_label + ".owl");
//        owl_model.write(f, "RDF/XML");
//
//        Map<String, Boolean> statusMap = new HashMap<>();
//
//        //生成数据model
//        BigFileReader.Builder builder = new BigFileReader.Builder(file_name, new IHandle() {
//			@Override
//			public void handle(String line) {}
//		});
//
//		builder.withThreadSize(threadNum)
//			   .withCharset(code)
//               .withHeaderURIs(headerURI)
//               .withDirectory(path + "/" + title + "/" + class_label)
//               .withBlockSize(blockSize)
//               .withInstanceURI(instanceUri)
//               .withClassURI(classUri)
//			   .withBufferSize(1024 * 1024);
//		BigFileReader bigFileReader = builder.build();
//        bigFileReader.start(start_index, statusMap);
//
//        while (statusMap.get("finished") == null || !statusMap.get("finished")) {
//            try {
//                Thread.sleep(3000);
//            } catch (InterruptedException e) {
//                e.printStackTrace();
//            }
//        }
//
////        System.out.println("111111111111111111");
//    }

    public static void addNodeStatements(Model owlModel, ExtractionContext extractionContext) {
        String nick = extractionContext.getNickName();
        String baseUri = extractionContext.getBaseURI();
        String title = extractionContext.getTitle();

        String classUri = baseUri + "/" + nick.substring(0, 1).toUpperCase() + nick.substring(1);

        owlModel.add(owlModel.createResource(classUri), RDF.type, owlModel.createResource(RDFS.Class.toString()));
        owlModel.add(owlModel.createResource(classUri), RDFS.label, owlModel.createLiteral(nick, "en")); //nick为英文
        owlModel.add(owlModel.createResource(classUri), RDFS.isDefinedBy, owlModel.createResource(classUri));

        if (!StringUtil.isBlank(title)) {
            owlModel.add(owlModel.createResource(baseUri), owlModel.createProperty(DC.title.toString()), owlModel.createLiteral(title));
        }
    }

    public static void addGraphStatements(Model owlModel, ExtractionContext extractionContext) {
        String version = extractionContext.getVersion();
        String creator = extractionContext.getCreator();
        String baseUri = extractionContext.getBaseURI();

        baseUri = baseUri + "/";

        owlModel.add(owlModel.createResource(baseUri), RDF.type, owlModel.createResource(OWL.Ontology.toString()));

        if (!StringUtil.isBlank(creator)) {
            owlModel.add(owlModel.createResource(baseUri), owlModel.createProperty(DC.creator.toString()), owlModel.createLiteral(creator));
        }

        if (!StringUtil.isBlank(version)) {
            owlModel.add(owlModel.createResource(baseUri), owlModel.createProperty(OWL.versionInfo.toString()), owlModel.createLiteral(version));
        }

//        if (!StringUtil.isBlank(title)) {
//            owlModel.add(owlModel.createResource(baseUri), owlModel.createProperty(DC.title.toString()), owlModel.createLiteral(title));
//        }
    }

    public static void generateOWLStatements(Model owlModel, URI[] headerURIs, String[] line, String[] line_zh, ExtractionContext extractionContext) {
        String baseURI = extractionContext.getBaseURI();
        String classUri = extractionContext.getClassURI();
        String classLabel = extractionContext.getClassLabel();
        String lang = extractionContext.getLang();
        String nick = extractionContext.getNickName();
        String description = extractionContext.getDescription();
        String isPublic = extractionContext.getIsPublic();

        baseURI = baseURI + "/";

        Resource resource = owlModel.createResource(classUri);

        //Construct class statements
        owlModel.add(resource, RDF.type, owlModel.createResource(RDFS.Class.toString()));

//        if (owlModel.contains(resource, RDFS.label)) {
//            owlModel.remove(resource, RDFS.label, (RDFNode)null);
//        }
        owlModel.add(resource, RDFS.label, owlModel.createLiteral(classLabel, lang));

        if (StringUtils.isNotBlank(nick)) {
            owlModel.add(resource, RDFS.isDefinedBy, owlModel.createResource(baseURI + nick.substring(0, 1).toUpperCase() + nick.substring(1)));
        } else {
            owlModel.add(resource, RDFS.isDefinedBy, owlModel.createResource(baseURI));
        }

        if (StringUtils.isNotBlank(nick)) {
            String node = baseURI + nick.substring(0, 1).toUpperCase() + nick.substring(1);
            owlModel.add(resource, RDFS.subClassOf, owlModel.createResource(node));
        }

        if (StringUtils.isNotBlank(description)) {
//            if (owlModel.contains(resource, DC.description)) {
//                owlModel.remove(resource, DC.description, (RDFNode)null);
//            }
            owlModel.add(resource, DC.description, owlModel.createLiteral(description));
        }

        if (StringUtils.isNotBlank(isPublic)) {
            owlModel.add(resource, owlModel.createProperty(USS.isPublic.toString()), isPublic); //true or false
        }

        //Construct property statments
        for (int i=0; i<headerURIs.length; i++) {
            String ps = "";

            //判断多语种
            if (headerURIs[i].toString().contains("@")) {
                ps = headerURIs[i].toString().split("\\@")[0];
//                lang = headerURIs[i].toString().split("@")[1];
            } else {
                ps = headerURIs[i].toString();
            }

            Resource p = owlModel.createProperty(ps);

            if (line[i].startsWith("http://")) {
                String l = line[i];
                if (l.contains("/")) {
                    owlModel.add(p, RDFS.label, owlModel.createLiteral(l.substring(l.lastIndexOf("/") + 1, l.length())));
                } else if (l.contains("#")) {
                    owlModel.add(p, RDFS.label, owlModel.createLiteral(l.substring(l.lastIndexOf("#") + 1, l.length())));
                }
            } else {
                owlModel.add(p, RDFS.label, owlModel.createLiteral(line[i]));
            }

            if (!StringUtil.isBlank(line_zh[i])) {
                owlModel.add(p, RDFS.label, owlModel.createLiteral(line_zh[i], lang));
            }

            owlModel.add(p, RDF.type, owlModel.createResource(com.lsh.streamgd.vocabulary.RDF.Property.toString()))
                    .add(p, RDFS.isDefinedBy, owlModel.createResource(baseURI))
                    .add(p, RDFS.domain, owlModel.createResource(classUri))
                    .add(p, RDFS.range, owlModel.createResource(com.lsh.streamgd.vocabulary.RDFS.Literal.toString()));
        }
    }

    public static URI[] processHeader(String[] header, URI documentURI) {
        URI[] result = new URI[header.length];
        int index = 0;
        for (String h : header) {
            String candidate = h.trim();
            if (RDFUtils.isAbsoluteURI(candidate)) {
                result[index] = new URIImpl(candidate);
            } else {
                result[index] = normalize(candidate, documentURI);
            }
            index++;
        }
        return result;
    }

    private static URI normalize(String toBeNormalized, URI documentURI) {
        toBeNormalized = toBeNormalized.trim().toLowerCase().replace("?", "").replace("&", "");

        StringBuilder result = new StringBuilder(documentURI.toString() + "/");

        StringTokenizer tokenizer = new StringTokenizer(toBeNormalized, " ");
        while (tokenizer.hasMoreTokens()) {
            String current = tokenizer.nextToken();

            result.append(current + "_");
        }

        //Construct property rule
        if (result.toString().endsWith("_")) {
            result = new StringBuilder(result.toString().substring(0, result.toString().length() - 1));
        }

        return new URIImpl(result.toString());
    }
}